package pl.gettoknowme.mobile.android.integration;

import pl.gettoknowme.mobile.android.MainActivity;
import pl.gettoknowme.mobile.android.model.DBAdapter;
import pl.gettoknowme.mobile.android.model.dao.UserSettingsDAO;
import pl.gettoknowme.mobile.android.model.dbtypes.Integration;
import pl.gettoknowme.mobile.android.model.dbtypes.UserSettings;
import pl.gettoknowme.mobile.android.model.dbtypes.Integration.IntegrationType;
import pl.gettoknowme.mobile.android.util.Constants;
import pl.gettoknowme.mobile.android.util.LoggingUtil;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;

/**
 * Odbiorca komunikatów o rozpoczęciu okresowej integracji
 * @author Michał Kołodziejski
 */
public class PeriodicalIntegrationReceiver extends BroadcastReceiver {
    
    public static final String DO_INTEGRATION_ACTION = 
        "pl.gettoknowme.mobile.android.integration.DO_INTEGRATION";
    
    public static final String START_PERIODICAL_INTEGRATION_ACTION = 
        "pl.gettoknowme.mobile.android.integration.START_PERIODICAL_INTEGRATION";
    
    public static final String STOP_PERIODICAL_INTEGRATION_ACTION = 
        "pl.gettoknowme.mobile.android.integration.STOP_PERIODICAL_INTEGRATION";
    
    /**
     * Interwał pomiędzy kolejnymi próbami integracji.
     * 60 minut.
     */
    public static final long INTEGRATION_INTERVAL = 1000l * 60l * 60l;
    

    @Override
    public void onReceive(Context context, Intent intent) {
        
        if (DO_INTEGRATION_ACTION.equals(intent.getAction())){
            LoggingUtil.d(this, "DO_INTEGRATION_ACTION catched - starting integration");
            
            doIntegration(context);
            return;
            
        } else if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())){
            LoggingUtil.d(this, "BOOT_COMPLETED catched - setting up AlarmManager");
            
            setupAlarmManager(context);
            return;
            
        } else if (START_PERIODICAL_INTEGRATION_ACTION.equals(intent.getAction())){
            LoggingUtil.d(this, "START_PERIODICAL_INTEGRATION_ACTION catched - setting up AlarmManager");
            
            setupAlarmManager(context);
            return;
            
        } else if (STOP_PERIODICAL_INTEGRATION_ACTION.equals(intent.getAction())){
            LoggingUtil.d(this, "STOP_PERIODICAL_INTEGRATION_ACTION catched - stopping AlarmManager");
            
            stopPeriodicalIntegration(context);
            return;
        }
    }
    
    
    public static boolean isPeriodicalIntegrationRunning(Context context){
        Intent intent = new Intent(DO_INTEGRATION_ACTION);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 
                PendingIntent.FLAG_NO_CREATE);
        return (pendingIntent != null);
    }

    
    /**
     * Rozpoczyna pojedynczą integrację
     * @param context kontekst działania
     */
    private void doIntegration(Context context){
        DBAdapter dbAdapter = DBAdapter.getInstance(context);
        
        // pobranie danych o uzytkowniku i poprzednich integracjach
        UserSettingsDAO usDAO = dbAdapter.getUserSettingsDAO();
        UserSettings userSettings = usDAO.getUserSettings();
        
        Integration lastSuccessfulLocationIntegration = dbAdapter.getIntegrationDAO()
                .getLastSuccessfulIntegration(IntegrationType.LOCATION);
        Integration lastSuccessfulCallsStatsIntegration = dbAdapter.getIntegrationDAO()
                .getLastSuccessfulIntegration(IntegrationType.CALLS_STATS);
        Integration lastSuccessfulSmsStatsIntegration = dbAdapter.getIntegrationDAO()
                .getLastSuccessfulIntegration(IntegrationType.SMS_STATS);
        
        // wystartowanie poszczególnych części integracji
        startLocationIntegration(userSettings, lastSuccessfulLocationIntegration, context);

        // ze względu na wyścig wątków - dodanie uśpienia przed drugą akcją
        sleep(1000l * 3l);
        
        startCallsStatsIntegration(userSettings, lastSuccessfulCallsStatsIntegration, context);
        
        startSmsIntegration(userSettings, lastSuccessfulSmsStatsIntegration, context);
        
        // analiza płci
        if(!wasUserSexAnalyzed(context)){
            startSexAnalysisIntegration(userSettings, context);
        }
    }
    
    private void sleep(long millis){
        try {
            LoggingUtil.d(this, "sleeping for "+millis+" milliseconds");
            Thread.sleep(millis);
            
        } catch (InterruptedException e) {
            LoggingUtil.e(this, "InterruptedException occured while sleeping", e);
        }
    }
    
    
    /**
     * Ustawia okresową integrację
     * @param context kontekst działania
     */
    private void setupAlarmManager(Context context){
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        
        PendingIntent pendingIntent = createDoIntegrationPendingIntent(context);
        long firstTrigger = System.currentTimeMillis() + 1000l * 60l * 5l; // za 5 min.
        
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, firstTrigger, INTEGRATION_INTERVAL, pendingIntent);
    }
    
    /**
     * Zatrzymuje okresową integrację
     * @param context kontekst działania
     */
    private void stopPeriodicalIntegration(Context context){
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

        PendingIntent pendingIntent = createDoIntegrationPendingIntent(context);
        alarmManager.cancel(pendingIntent);
        pendingIntent.cancel();
    }
    
    /**
     * Tworzy PendingIntent powiadamiający o rozpoczęciu okresowej integracji
     * @param context kontekst działania
     * @return PendingIntent powiadamiający o rozpoczęciu okresowej integracji
     */
    private PendingIntent createDoIntegrationPendingIntent(Context context){
        Intent intent = new Intent(DO_INTEGRATION_ACTION);
        return PendingIntent.getBroadcast(context, 0, intent, 
                PendingIntent.FLAG_UPDATE_CURRENT);
    }
    
    /**
     * Uruchamia integrację lokalizacji
     * @param userSettings ustawienia użytkownika
     * @param lastSuccessfulIntegration ostatnia pomyślna integracja
     * @param context kontekst działania
     */
    private void startLocationIntegration(UserSettings userSettings, Integration lastSuccessfulIntegration, 
            Context context){
        Long lastSuccessfulIntegrationTime = null;
        if(lastSuccessfulIntegration != null){
            lastSuccessfulIntegrationTime = lastSuccessfulIntegration.getIntegrationTime();
        }
        
        Thread th = new Thread(new LocationIntegrationRunnable(context, userSettings.getUserId(), 
                lastSuccessfulIntegrationTime));
        th.start();
    }
    
    /**
     * Uruchamia integrację statystyk SMS-ów
     * @param userSettings ustawienia użytkownika
     * @param lastSuccessfulIntegration ostatnia pomyślna integracja
     * @param context kontekst działania
     */
    private void startSmsIntegration(UserSettings userSettings, Integration lastSuccessfulIntegration, 
            Context context){
        Long lastSuccessfulIntegrationTime = null;
        if(lastSuccessfulIntegration != null){
            lastSuccessfulIntegrationTime = lastSuccessfulIntegration.getIntegrationTime();
        }
        
        Thread th = new Thread(new SmsStatsIntegrationRunnable(context, userSettings.getUserId(), 
                lastSuccessfulIntegrationTime));
        th.start();
    }
    
    /**
     * Uruchania integrację statystyk połączeń telefonicznych
     * @param userSettings ustawienia użytkownika
     * @param lastSuccessfulIntegration ostatnia pomyślna integracja
     * @param context kontekst działania
     */
    private void startCallsStatsIntegration(UserSettings userSettings, Integration lastSuccessfulIntegration, 
            Context context){
        Long lastSuccessfulIntegrationTime = null;
        if(lastSuccessfulIntegration != null){
            lastSuccessfulIntegrationTime = lastSuccessfulIntegration.getIntegrationTime();
        }
        
        Thread th = new Thread(new CallsStatsIntegrationRunnable(context, userSettings.getUserId(),
                lastSuccessfulIntegrationTime));
        th.start();
    }
    
    /**
     * Zwraca informację czy płeć użytkownika została już przeanalizowana
     * @param context kontekst wykonania
     * @return true jeżeli płeć została przeanalizowana, false w p.p.
     */
    private boolean wasUserSexAnalyzed(Context context){
        SharedPreferences sharedPreferences = context.getSharedPreferences(MainActivity.class.getName(), 
                Context.MODE_PRIVATE);
        return sharedPreferences.getBoolean(Constants.USER_SEX_ANALYZED_SHARED_PREFERENCES_KEY, false);
    }
    
    /**
     * Uruchamia analizę i integrację dot. płci użytkownika
     * @param userSettings ustawienia użytkownika
     * @param context kontekst działania
     */
    private void startSexAnalysisIntegration(UserSettings userSettings, Context context){
        Thread th = new Thread(new SexAnalysisIntegrationRunnable(context, userSettings.getUserId()));
        th.start();
    }
}
